/*
 * Copyright (C) 2013 Daniel Wasilew <daniel.wasilew@codeminer.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.codeminer.parts.database.dao;

import org.codeminer.database.DatabaseConnection;
import org.codeminer.database.DatabaseException;
import org.codeminer.parts.database.sql.SQL;
import org.codeminer.parts.library.Identifiable;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

/**
 *
 * @author Daniel Wasilew <daniel.wasilew@codeminer.org>
 */
abstract class DAO {

    /**
     * gets and writes the next OId to the Informationtable
     *
     * Writelock should be accuired before and released after this method
     *
     * @param connection
     * @throws DatabaseException if an error occurs
     */
    static void updateAndGetNextId(DatabaseConnection connection, Identifiable identifiable) throws DatabaseException {
        ResultSet result = null;
        try {
            String sql = SQL.select("Prop_Value").from("DatabaseInformation").where("Property").like("NEXT_ID").toSQL();
            result = connection.createStatement().executeQuery(sql);
            if (result.next()) {
                long currentId = result.getLong("Prop_Value");
                currentId++;
                connection.createStatement().executeUpdate(SQL.update("Databaseinformation").set("Prop_Value", "" + currentId).where("Property").like("NEXT_ID").toSQL());
                identifiable.setOid(currentId);
            } else {
                throw new DatabaseException("Could not fetch nextID");
            }
        } catch (SQLException ex) {
            throw new DatabaseException(ex);
        } finally {
            if (result != null) {
                try {
                    result.close();
                } catch (SQLException ignored) {

                }
            }
        }
    }

    static void validateIdentifiables(Identifiable first, Identifiable... others) {
        validateIdentifiable(first);
        for (Identifiable identifiable : others) {
            validateIdentifiable(identifiable);
        }
    }

    static void validateIdentifiable(Identifiable identifiable) {
        if (identifiable.getOid() < 0) {
            throw new IllegalArgumentException("identifiable [" + identifiable.getClass() + "] is not persisted");
        }
    }

    static void executeInsert(DatabaseConnection connection, String insertStatement) throws DatabaseException {
        try {
            connection.createStatement().executeUpdate(insertStatement);
        } catch (SQLException ex) {
            throw new DatabaseException(ex);
        }
    }

    static boolean executeUpdate(DatabaseConnection connection, String deleteStatement) throws DatabaseException {
        try {
            int affectedRows = connection.createStatement().executeUpdate(deleteStatement);
            return affectedRows == 1;
        } catch (SQLException ex) {
            throw new DatabaseException(ex);
        }
    }

    static List<Long> queryIds(String query, String queryId, DatabaseConnection connection) throws DatabaseException {
        ResultSet resultSet = null;
        try {
            resultSet = connection.createStatement().executeQuery(query);
            List<Long> songIds = new LinkedList<>();
            while (resultSet.next()) {
                songIds.add(resultSet.getLong(queryId));
            }
            return songIds;
        } catch (SQLException ex) {
            throw new DatabaseException(ex);
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException ignored) {
                }
            }
        }
    }

    protected static <T> T getSingleProperty(String query, String propertyColumnName, DatabaseConnection connection) throws DatabaseException {
        ResultSet resultSet = null;
        try {
            resultSet = connection.createStatement().executeQuery(query);
            T result = null;
            while (resultSet.next()) {
                if (result != null) {
                    throw new DatabaseException("more than one row found for [" + query + "]");
                }
                result = (T) resultSet.getObject(propertyColumnName);
            }
            return result;
        } catch (SQLException ex) {
            throw new DatabaseException(ex);
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException ignored) {
                }
            }
        }
    }

    protected static <T> List<T> getPropertyList(String query, String propertyColumnName, DatabaseConnection connection) throws DatabaseException {
        ResultSet resultSet = null;
        try {
            resultSet = connection.createStatement().executeQuery(query);
            List<T> result = new LinkedList<>();
            while (resultSet.next()) {
                result.add((T) resultSet.getObject(propertyColumnName));
            }
            return result;
        } catch (SQLException ex) {
            throw new DatabaseException(ex);
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException ignored) {

                }
            }
        }
    }
}
